package com.easy.query.core.proxy;

import com.easy.query.core.basic.api.select.Query;
import com.easy.query.core.expression.RelationEntityTableAvailable;
import com.easy.query.core.expression.lambda.SQLActionExpression;
import com.easy.query.core.expression.lambda.SQLExpression1;
import com.easy.query.core.expression.lambda.SQLFuncExpression;
import com.easy.query.core.expression.lambda.SQLFuncExpression1;
import com.easy.query.core.expression.parser.core.SQLTableOwner;
import com.easy.query.core.func.SQLFunc;
import com.easy.query.core.proxy.core.Expression;
import com.easy.query.core.proxy.extension.functions.executor.ColumnFunctionComparableDateTimeChainExpression;
import com.easy.query.core.proxy.extension.functions.executor.impl.ColumnFunctionComparableDateTimeChainExpressionImpl;
import com.easy.query.core.proxy.impl.SQLColumnIncludeColumn2Impl;
import com.easy.query.core.proxy.impl.SQLConstantExpressionImpl;
import com.easy.query.core.proxy.impl.SQLDraftAsSelectImpl;
import com.easy.query.core.proxy.impl.SQLPredicateImpl;
import com.easy.query.core.proxy.impl.SQLSelectAllImpl;
import com.easy.query.core.proxy.impl.SQLSelectAsEntryImpl;
import com.easy.query.core.proxy.impl.SQLSelectIgnoreImpl;
import com.easy.query.core.proxy.impl.SQLSelectKeysImpl;
import com.easy.query.core.proxy.sql.scec.SQLNativeProxyExpressionContext;
import com.easy.query.core.util.EasyObjectUtil;

import java.time.LocalDateTime;
import java.util.function.Consumer;
import java.util.function.Supplier;

/**
 * create time 2023/6/25 12:39
 * 文件说明
 *
 * @author xuejiaming
 */
public abstract class AbstractProxyEntity<TProxy extends ProxyEntity<TProxy, TEntity>, TEntity> extends AbstractBaseProxyEntity<TProxy, TEntity> {

    protected <TPropertyProxy extends SQLColumn<TProxy, TProperty>, TProperty> TPropertyProxy getValueObject(TPropertyProxy propertyProxy) {
        propertyProxy._setProxy(castChain());
        return propertyProxy;
    }

    protected String getValueProperty(String property) {
        return property;
    }

    public void or(SQLActionExpression sqlActionExpression){
        or(true,sqlActionExpression);
    }
    public void or(boolean condition,SQLActionExpression sqlActionExpression){
        if(condition){
            getEntitySQLContext()._whereOr(sqlActionExpression);
        }
    }

    public void and(SQLActionExpression sqlActionExpression){
        and(true,sqlActionExpression);
    }
    public void and(boolean condition,SQLActionExpression sqlActionExpression){
        if(condition){
            getEntitySQLContext()._whereAnd(sqlActionExpression);
        }
    }

    /**
     * 支持where having order
     * 请使用{@link #expression()}或者{@link Expression#sql(String)}
     * @param sqlSegment
     */
    @Deprecated
    public void executeSQL(String sqlSegment){
        executeSQL(sqlSegment, c->{});
    }

    /**
     * 支持where having order
     * 请使用{@link #expression()}或者{@link Expression#sql(String, SQLExpression1)}
     *
     * @param sqlSegment
     * @param contextConsume
     */
    @Deprecated
    public void executeSQL(String sqlSegment, SQLExpression1<SQLNativeProxyExpressionContext> contextConsume){
        executeSQL(true,sqlSegment,contextConsume);
    }

    /**
     * 支持where having order
     * 请使用{@link #expression()}或者{@link Expression#sql(boolean, String, SQLExpression1)}
     *
     * @param condition
     * @param sqlSegment
     * @param contextConsume
     */
    @Deprecated
    public void executeSQL(boolean condition, String sqlSegment, SQLExpression1<SQLNativeProxyExpressionContext> contextConsume){
        if(condition){
            getEntitySQLContext()._executeNativeSql(sqlSegment,contextConsume);
        }
    }
    protected <T, N> N __cast(T original){
        return EasyObjectUtil.typeCastNullable(original);
    }


//    /**
//     * 返回group或者selectDraft自定义sql片段
//     * 请使用{@link #expression()}或者{@link Expression#sqlType(String)}
//     * <blockquote><pre>
//     * {@code
//     *
//     *  .select((t, t1, t2) -> new QueryVOProxy() {{
//     *      t.sql("now()");
//     *      //指定返回类型给draft类型进行明确
//     *      //t.sql("now()").setPropertyType(String.class);
//     *  }}).toList();
//     * }
//     * </blockquote></pre>
//     * @param sqlSegment
//     * @return
//     */
//    @Deprecated
//    public PropTypeColumn<Object> sql(String sqlSegment) {
//        return sql(sqlSegment, c->{});
//    }

//    /**
//     * 返回group或者selectDraft自定义sql片段
//     * 请使用{@link #expression()}或者{@link Expression#sqlType(String,SQLExpression1)}
//     * <blockquote><pre>
//     * {@code
//     *
//     *  .select((t, t1, t2) -> new QueryVOProxy() {{
//     *      t.sql("IFNull({0},{1})",c->c.expression(t.id()).value("1"));
//     *      //指定返回类型给draft类型进行明确
//     *      //t.sql("IFNull({0},{1})",c->c.expression(t.id()).value("1")).setPropertyType(String.class);
//     *  }}).toList();
//     * }
//     * </blockquote></pre>
//     * @param sqlSegment 片段
//     * @param contextConsume 片段参数
//     * @return 返回元素sql片段
//     */
//    @Deprecated
//    public PropTypeColumn<Object> sql(String sqlSegment, SQLExpression1<SQLNativeProxyExpressionContext> contextConsume) {
//        return new SQLNativeDraftImpl(entitySQLContext,(alias, f) -> {
//            f.sqlNativeSegment(sqlSegment, c -> {
//                if (alias != null) {
//                    c.setPropertyAlias(alias);
//                }
//                contextConsume.apply(new SQLNativeProxyExpressionContextImpl(c));
//            });
//        });
//    }

    /**
     * 返回子查询
     * 请使用 {@link #expression()}或者{@link Expression#subQuery(SQLFuncExpression)}
     * <blockquote><pre>
     * {@code
     *      o.subQuery(()->{
     *          return easyEntityQuery.queryable(x.class).select(x->new StringProxy(x.id()));
     *      })
     *  }
     * </pre></blockquote>
     * @param subQueryableFunc 创建子查询方法
     * @return
     * @param <TSubQuery>
     */
    @Deprecated
    public <TSubQuery> PropTypeColumn<TSubQuery> subQuery(SQLFuncExpression<Query<TSubQuery>> subQueryableFunc) {
        Query<TSubQuery> subQueryQuery = subQueryableFunc.apply();
        return new SQLDraftAsSelectImpl<>((alias, f)->{
            f.columnSubQueryAs(()->subQueryQuery, alias);
        },subQueryQuery.queryClass());
    }

    /**
     * 所有主键列
     * @return 选择所有主键列的表达式
     */
    public SQLSelectAsExpression columnKeys() {
        return new SQLSelectKeysImpl(this.getEntitySQLContext(),getTable());
    }

    /**
     * 请使用{@link #expression()}或者{@link Expression#now()}
     * @return
     */
    @Deprecated
    public ColumnFunctionComparableDateTimeChainExpression<LocalDateTime> _now() {
        return new ColumnFunctionComparableDateTimeChainExpressionImpl<>(this.getEntitySQLContext(),null, null, SQLFunc::now,LocalDateTime.class);
    }

    /**
     * 请使用{@link #expression()}或者{@link Expression#utcNow()}
     * @return
     */
    @Deprecated
    public ColumnFunctionComparableDateTimeChainExpression<LocalDateTime> _utcNow() {
        return new ColumnFunctionComparableDateTimeChainExpressionImpl<>(this.getEntitySQLContext(),null, null, SQLFunc::utcNow,LocalDateTime.class);
    }

    /**
     * 查询表所有属性字段,如果前面已经单独查询了那么会追加下去
     *
     * <blockquote><pre>
     * {@code
     *  //选择o表所有属性
     *  .select(o->new ResultProxy().selectAll(o));
     *  //选择o表所有属性上下两种写法都可以
     *  .select(o->new ResultProxy().adapter(x->{
     *     x.selectAll(o);
     *  }));
     *  }
     * </pre></blockquote>
     * @param proxy
     * @return
     * @param <TRProxy>
     * @param <TREntity>
     */
    public <TRProxy extends ProxyEntity<TRProxy, TREntity>, TREntity> TProxy selectAll(TRProxy proxy) {
        entitySQLContext.accept(new SQLSelectAllImpl(proxy.getEntitySQLContext(),proxy.getTable(), new TablePropColumn[0]));
        return castChain();
    }

    /**
     * 忽略前面所选的
     * <blockquote><pre>
     * {@code
     *  //选择o表所有属性但是忽略id和name
     *  .select(o->new ResultProxy().selectAll(o).selectIgnores(o.id(),o.name()));
     *  //选择o表所有属性但是忽略id和name 上下两种写法都可以
     *  .select(o->new ResultProxy().adapter(x->{
     *     x.selectAll(o).selectIgnores(o.id(),o.name()));
     *  }));
     *  }
     * </pre></blockquote>
     * @param ignoreTableProps
     * @return
     * @param <TRProxy>
     * @param <TREntity>
     */
    public <TRProxy extends ProxyEntity<TRProxy, TREntity>, TREntity> TProxy selectIgnores(TablePropColumn... ignoreTableProps) {
        entitySQLContext.accept(new SQLSelectIgnoreImpl(ignoreTableProps));
        return castChain();
    }

    /**
     * 快速选择表达式
     * <blockquote><pre>
     * {@code
     *
     *  .select(o->new ResultProxy().selectExpression(o.id(),o.name()));
     *
     *  .select(o->new ResultProxy().adapter(x->{
     *      x.selectExpression(o.id(),o.name());
     *  }));
     *  }
     * </pre></blockquote>
     * @param sqlSelectAsExpression 要查询的表达式
     */
    public TProxy selectExpression(SQLSelectAsExpression... sqlSelectAsExpression) {
        entitySQLContext.accept(sqlSelectAsExpression);
        return castChain();
    }
    /**
     * 支持动态select+动态group取列防止sql注入
     * @param sqlTableOwner 要查询的表
     * @param property 要查询的属性
     */
    public TProxy selectColumn(SQLTableOwner sqlTableOwner, String property) {
        entitySQLContext.accept(new SQLSelectAsEntryImpl(this.getEntitySQLContext(),sqlTableOwner.getTable(),property));
        return castChain();
    }
    /**
     * 支持动态select+动态selectAs取列防止sql注入
     * @param sqlTableOwner 要查询的表
     * @param property 要查询的属性
     * @param propertyAlias 要查询的属性别名映射到返回结果的属性名称
     */
    public TProxy selectColumnAs(SQLTableOwner sqlTableOwner,String property,String propertyAlias) {
        entitySQLContext.accept(new SQLSelectAsEntryImpl(this.getEntitySQLContext(),sqlTableOwner.getTable(),property,propertyAlias));
        return castChain();
    }


//    /**
//     * 快速选择表达式
//     * <blockquote><pre>
//     * {@code
//     *
//     *  .select(t -> {
//     *         TopicProxy topicProxy = new TopicProxy();
//     *         topicProxy.clientSelect(selector -> {
//     *             selector.column(t.getTable(), "id");
//     *             selector.column(t.getTable(), "title");
//     *         });
//     *         return topicProxy;
//     *     })
//     *  }
//     * </pre></blockquote>
//     **/
//    public void clientSelect(Consumer<AsSelector> selectorConsumer) {
//        entitySQLContext.accept(new SQLSelectAsOnlyImpl(this.getTable(),this.getEntitySQLContext(),selectorConsumer));
//    }

    /**
     * 增强当前代理对象
     * @param selectExpression 选择表达式
     * @return 返回增强后的当前代理对象
     */
    public TProxy adapter(Consumer<TProxy> selectExpression) {
        selectExpression.accept(castChain());
        return castChain();
    }

    /**
     * {@link #expression()}或者{@link Expression#exists(Supplier)}
     * where exists(....)
     * @param subQueryFunc 子查询创建方法
     */
    @Deprecated
    public void exists(Supplier<Query<?>> subQueryFunc) {
        exists(true, subQueryFunc);
    }

    /**
     * {@link #expression()}或者{@link Expression#exists(boolean,Supplier)}
     * where exists(....)
     * @param condition 为true是exists生效
     * @param subQueryFunc 子查询创建方法
     */
    @Deprecated
    public void exists(boolean condition, Supplier<Query<?>> subQueryFunc) {
        if (condition) {
            getEntitySQLContext().accept(new SQLPredicateImpl(f -> f.exists(subQueryFunc.get())));
        }
    }

    /**
     * {@link #expression()}或者{@link Expression#notExists(Supplier)}
     * where not exists(....)
     * @param subQueryFunc 子查询创建方法
     */
    @Deprecated
    public void notExists(Supplier<Query<?>> subQueryFunc) {
        notExists(true, subQueryFunc);
    }


    /**
     * {@link #expression()}或者{@link Expression#notExists(boolean, Supplier)}
     * where exists(....)
     * @param condition 为true是not exists生效
     * @param subQueryFunc 子查询创建方法
     */
    @Deprecated
    public void notExists(boolean condition, Supplier<Query<?>> subQueryFunc) {
        if (condition) {
            getEntitySQLContext().accept(new SQLPredicateImpl(f -> f.notExists(subQueryFunc.get())));
        }
    }

    /**
     * 请使用SQLConstant方法
     * @return 数据库常量值构建方法
     */
    @Deprecated
    public SQLConstantExpression SQLParameter(){
        return new SQLConstantExpressionImpl(this.getEntitySQLContext());
    }

    /**
     * {@link #expression()}或者{@link Expression#constant()}
     * 创建常量值用于比较或者处理
     * @return 数据库常量值构建方法
     */
    @Deprecated
    public SQLConstantExpression SQLConstant(){
        return new SQLConstantExpressionImpl(this.getEntitySQLContext());
    }
    public Expression expression(){
        return Expression.of(entitySQLContext);
    }
    public <TPropertyProxy extends ProxyEntity<TPropertyProxy,TProperty>, TProperty> void set(TPropertyProxy columnProxy) {
        set(columnProxy,null);
    }
    public <TPropertyProxy extends ProxyEntity<TPropertyProxy,TProperty>, TProperty> void set(TPropertyProxy columnProxy, SQLFuncExpression1<TPropertyProxy, ProxyEntity<TProxy, TEntity>> navigateSelectExpression) {
        getEntitySQLContext().accept(new SQLColumnIncludeColumn2Impl<>(((RelationEntityTableAvailable)columnProxy.getTable()).getOriginalTable(), columnProxy.getNavValue(), getNavValue(),columnProxy,navigateSelectExpression));
    }
}
